﻿using Core.Log;
using Core.Utility.Extendsions.Regex;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Core.Utility.Helper
{
    /// <summary>
    /// 字符串助手类
    /// </summary>
    public static class StringHelper
    {
        /// <summary>
        /// <see cref="string.Format(string, object?[])"/>的format字符串的标准化
        /// <para> 当 args.Count &lt; format 表达式的总数时；将插入 null 至 args 中</para>
        /// <para> 当 format 表达式的总数 &lt; args.Count 时; format 将遍历format的表达式索引，寻找缺少的索引，将表达式插入至format最后</para>
        /// </summary>
        /// <param name="format">格式化文本</param>
        /// <param name="args">格式化参数列表</param>
        /// <param name="regexTimeOut">正则超时时间（单位：秒）</param>
        /// <returns></returns>
        public static string StringFormatStringStand(this string format,List<object?> args, double regexTimeOut = 2)
        {
            //获取StringFormat中的替换字符参数：例如：{0,-10:C}、{0}、{0,1}、{0:g}
            //var stringFormatRegexMatches = format.GetStringFormatExpressionList(regexTimeOut);

            //缺失表达式列表
            var missingExpressionList = new List<string>();
            //提取表达式索引
            var stringFormatIndexList = format.GetStringFormatExpressionIndexList(regexTimeOut);
            var stringFormatIndexMaxValue = stringFormatIndexList.Count <= 0 ? 0 : stringFormatIndexList.Max();
            var findCount = args.Count > stringFormatIndexMaxValue + 1 ? args.Count : stringFormatIndexMaxValue + 1;
            for (int i = 0; i < findCount; i++)
            {
                //遍历查找，添加缺失的索引至末尾 ,处理 {0}{3}{9}这种场景
                if(!stringFormatIndexList.Contains(i))
                {
                    missingExpressionList.Add($"{{{i}}}");
                }
            }
            format = format + string.Join("", missingExpressionList);

            //处理表达式索引大于参数总数的场景
            if (findCount > args.Count)
            {
                //stringFormat匹配的参数列表大于 传入的参数列表；填充null补全
                int argsCount = args.Count;
                for (int i = 0; i < findCount - argsCount; i++)
                {
                    args.Add(null);
                }
            }
            return format;
        }

        /// <summary>
        /// 获取<see cref="string.Format(string, object?[])"/>中的格式化表达式列表，即:{0}、{0,-10:C}、{0,1}、{0:g}
        /// </summary>
        /// <param name="format">格式化字符串</param>
        /// <param name="regexTimeOut">正则超时时间（单位：秒）</param>
        /// <returns></returns>
        public static List<string> GetStringFormatExpressionList(this string format,double regexTimeOut = 2)
        {
            List<string> result = new List<string>();
            try
            {
                var stringFormatRegexMatches = Regex.Matches(format, RegexPatterns.StringFormatPattern, RegexOptions.None, TimeSpan.FromSeconds(2));
                foreach (Match stringFormatRegexMatch in stringFormatRegexMatches)
                {
                    result.Add(stringFormatRegexMatch.Value);
                }
            }
            catch(Exception ex)
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine($"调用方法：StringHelper.GetStringFormatExpression() 出错；");
                sb.AppendLine($"参数： format => {format}");
                sb.AppendLine($"参数： regexTimeOut => {regexTimeOut}");
                AppTrace.Logger.LogError(ex, sb.ToString());
            }
            return result;
        }

        /// <summary>
        /// 获取<see cref="string.Format(string, object?[])"/>中格式化表达式的所有列表，即:{0}、{1,-10:C}、{2,1}、{3:g} => 0,1,2,3
        /// </summary>
        /// <param name="format">格式化字符串</param>
        /// <param name="regexTimeOut">正则超时时间（单位：秒）</param>
        /// <returns></returns>
        public static List<int> GetStringFormatExpressionIndexList(this string format, double regexTimeOut = 2)
        {
            List<int> result = new List<int>();
            try
            {
                var indexRegexMatches = Regex.Matches(format, @"\{\d+", RegexOptions.None, TimeSpan.FromSeconds(regexTimeOut));
                //提取结果 {0} => {0 ; {1,-10:C} => {
                foreach (Match indexRegexMatch in indexRegexMatches)
                {
                    string? indexString = indexRegexMatch?.Value?.Replace("{", "");
                    int index = ValueTypeConvertHelper.ToInt(indexString, int.MinValue);
                    if (index != int.MinValue)
                    {
                        result.Add((int)index);
                    }
                }
            }
            catch (Exception ex)
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine($"调用方法：StringHelper.GetStringFormatExpressionIndexList() 出错；");
                sb.AppendLine($"参数： format => {format}");
                sb.AppendLine($"参数： regexTimeOut => {regexTimeOut}");
                AppTrace.Logger.LogError(ex, sb.ToString());
            }
            return result;

        }

        /// <summary>
        /// 最低限度脱敏
        /// </summary>
        /// <param name="original">原始字符串</param>
        /// <param name="readableLength">可读长度，若可读长度大于等于字符串长度，则保留最低脱敏长度</param>
        /// <param name="floorLength">最低脱敏长度，不能小于1</param>
        /// <param name="replacementChar">替换字符</param>
        /// <returns></returns>
        public static string FloorDesensitization(this string original, uint readableLength = 1, uint floorLength = 1, char replacementChar = '*')
        {
            if (readableLength >= original.Length)
            {
                if (floorLength <= 0)
                {
                    floorLength = 1;
                }
                else if(floorLength > original.Length)
                {
                    floorLength = original.Length.ToUInt();
                }
                readableLength = floorLength;
            }
            return Desensitization(original, readableLength, replacementChar);
        }

        /// <summary>
        /// 文本中间脱敏
        /// <para>如：张大彪 => 张*彪 ; 张彪=>张*</para>
        /// </summary>
        /// <param name="original">原始字符串</param>
        /// <param name="replacementChar">替换字符</param>
        /// <returns></returns>
        public static string TextMiddleDesensitization(this string? original, char replacementChar = '*')
        {
            //张三三 => readableLength = 1 => 张*三
            //张三三 => readableLength = 2 => 张**
            //计算隐藏字符串的开始索引
            if(original == null)
            {
                original = "";
            }
            uint readableLength = (original.Length).ToUInt();
            if (original.Length <= 2)
            {
                readableLength = 1;
            }
            else
            {
                readableLength = 2;
            }
            return Desensitization(original, readableLength, replacementChar);
        }

        /// <summary>
        /// 脱敏,根据可读长度，对原始字符串两侧进行均分保留，中间进行脱敏
        /// <para>如：司徒建国 => 司徒*国 ; 司徒建国=>司**国; 司徒建国=>司***</para>
        /// </summary>
        /// <param name="original">原始字符串</param>
        /// <param name="readableLength">可读长度，若可读长度大于原始字符串，则全加密</param>
        /// <param name="replacementChar">替换字符</param>
        /// <returns></returns>
        public static string Desensitization(this string? original, uint readableLength = 1, char replacementChar = '*')
        {
            int leftReadableLength = Math.Round(readableLength.ToDecimal() / 2, 0, MidpointRounding.ToPositiveInfinity).ToInt();
            int rightReadableLength = readableLength.ToInt() - leftReadableLength;
            if(rightReadableLength < 0)
            {
                rightReadableLength = 0;
            }
            return Desensitization(original, leftReadableLength.ToUInt(), rightReadableLength.ToUInt(), 1, replacementChar);
        }

        /// <summary>
        /// 脱敏
        /// </summary>
        /// <param name="original">原始字符串</param>
        /// <param name="leftReadableLength">左侧可读长度</param>
        /// <param name="rightReadableLength">右侧可读长度</param>
        /// <param name="floorLength">最低可读长度 大于等于1，若 原始字符串长度 - (左侧可读长度 + 右侧可读长度) &lt; 最低可读长度 ;则左侧可读长度强制为最低可读长度,右侧可读长度为0 </param>
        /// <param name="replacementChar">替换字符</param>
        /// <returns></returns>
        public static string Desensitization(this string? original, uint leftReadableLength = 1,uint rightReadableLength  = 1, uint floorLength = 1, char replacementChar = '*')
        {
            //张三三 => readableLength = 1 => 张*三
            //张三三 => readableLength = 2 => 张三三
            if (original == null)
            {
                original = "";
            }

            if (floorLength <= 0)
            {
                floorLength = 1;
            }

            if (original.Length - (leftReadableLength + rightReadableLength) < 0)
            {
                if (leftReadableLength + rightReadableLength >= floorLength)
                {
                    if (leftReadableLength < floorLength)
                    {
                        rightReadableLength = floorLength - leftReadableLength;
                    }
                    else
                    {
                        leftReadableLength = floorLength;
                        rightReadableLength = 0;
                    }
                }
                else
                {
                    if (leftReadableLength + rightReadableLength <= floorLength)
                    {
                        floorLength = 1;
                    }
                    leftReadableLength = Convert.ToUInt32(Math.Round(Convert.ToDecimal(floorLength) / 2, 0, MidpointRounding.ToPositiveInfinity));
                    rightReadableLength = Convert.ToUInt32(floorLength) - leftReadableLength;
                }
            }

            StringBuilder sbRes = new StringBuilder();
            char[] charS = original.ToArray();
            for (int i = 0; i < original.Length; i++)
            {
                if (i < leftReadableLength || i >= (original.Length - rightReadableLength))
                {
                    sbRes.Append(charS[i]);
                }
                else
                {
                    sbRes.Append(replacementChar);
                }
            }
            return sbRes.ToString();
        }

        private static readonly Regex reg = new Regex("^[一-龥a-zA-Z0-9]+$");

        /// <summary>
        /// 除开始外的匹配
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string? MatchExceptStart(this string? value)
        {
            int num = 0;
            int? num2 = value?.Length;
            if (value != null)
            {
                while (num2 > 0 && num2 > num)
                {
                    Match match = reg.Match(value, num, 1);
                    if (match.Success)
                    {
                        return new string(value.Skip(num).Take(num2.Value - num).ToArray());
                    }

                    num++;
                }
            }
            return value;
        }

        /// <summary>
        /// 匹配第一个
        /// </summary>
        /// <param name="body"></param>
        /// <param name="key"></param>
        /// <param name="isconse"></param>
        /// <returns></returns>
        public static string? MatchOne(this string body, string key, bool isconse = true)
        {
            return body.MatchAll(key, isconse, isone: true)?.FirstOrDefault();
        }

        /// <summary>
        /// 匹配所有
        /// </summary>
        /// <param name="body"></param>
        /// <param name="key"></param>
        /// <param name="isconse"></param>
        /// <param name="isone"></param>
        /// <returns></returns>
        public static List<string> MatchAll(this string body, string key, bool isconse = true, bool isone = false)
        {
            List<string> list = new List<string>();
            List<string> list2 = key.SplitsWithTrim("_???_");
            if (list2.Count == 2 && !string.IsNullOrWhiteSpace(list2[0]) && body.Contains(list2[0]))
            {
                int length = list2[0].Length;
                int num = body.IndexOf(list2[0]);
                int num2 = body.IndexOf(list2[1], num);
                while (num >= 0 && num2 >= 0)
                {
                    string text = body.Substring(num + length, num2 - num - length);
                    if (isconse)
                    {
                        text = list2[0] + text + list2[1];
                    }

                    list.Add(text);
                    if (isone)
                    {
                        break;
                    }

                    num = body.IndexOf(list2[0], num2);
                    num2 = ((num < 0) ? (-1) : body.IndexOf(list2[1], num));
                }
            }

            return list;
        }

        /// <summary>
        /// 获取Html匹配的值
        /// </summary>
        /// <param name="body"></param>
        /// <param name="match"></param>
        /// <returns></returns>
        public static string? GetHtmlMatchValue(this List<string> body, string match)
        {
            return body?.FirstOrDefault((string i) => i.Replace('"', '\'').Contains(match))?.GetHtmlMatchValue();
        }

        /// <summary>
        /// 获取Html匹配的值
        /// </summary>
        /// <param name="body"></param>
        /// <returns></returns>
        public static string? GetHtmlMatchValue(this string? body)
        {
            string? text = body?.Replace('"', '\'');
            if (text != null)
            {
                int num = text.IndexOf("value");
                if (num > 0)
                {
                    int num2 = text.IndexOf("'", num);
                    if (num2 > 0)
                    {
                        int num3 = text.IndexOf("'", num2 + 1);
                        if (num3 > 0)
                        {
                            return body?.Substring(num2 + 1, num3 - num2 - 1);
                        }
                    }
                }
            }
            return "";
        }

        /// <summary>
        /// 将对象转换为字符串
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string ToString(object? obj)
        {
            return obj?.ToString() ?? "";
        }

        /// <summary>
        /// 格式化
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="formate"></param>
        /// <returns></returns>
        public static string ToSFormate(decimal? obj, string formate = "0.0000")
        {
            if (obj.HasValue)
            {
                return obj.Value.ToString(formate);
            }

            return 0.ToString(formate);
        }

        /// <summary>
        /// 替换最后一个
        /// </summary>
        /// <param name="str"></param>
        /// <param name="oldStr"></param>
        /// <param name="newStr"></param>
        /// <param name="comparisonType"></param>
        /// <returns></returns>
        public static string? ReplaceLast(this string? str, string? oldStr, string? newStr, StringComparison comparisonType = StringComparison.CurrentCultureIgnoreCase)
        {
            if (!string.IsNullOrWhiteSpace(str))
            {
                newStr = newStr ?? string.Empty;
                if(oldStr == null)
                {
                    oldStr = "";
                }
                int num = str.LastIndexOf(oldStr, comparisonType);
                if (num != -1)
                {
                    return str.Remove(num, oldStr.Length).Insert(num, newStr);
                }
            }

            return str;
        }

        /// <summary>
        /// 全部替换为空
        /// </summary>
        /// <param name="str"></param>
        /// <param name="oldStr"></param>
        /// <returns></returns>
        public static string ReplaceAllToSpace(this string str, List<string> oldStr)
        {
            oldStr.ForEach(delegate (string i)
            {
                str = str.Replace(i, "");
            });
            return str;
        }

        /// <summary>
        /// 全部替换为空
        /// </summary>
        /// <param name="str"></param>
        /// <param name="oldStr"></param>
        /// <returns></returns>
        public static string ReplaceAllToSpace(this string str, params string[] oldStr)
        {
            oldStr.Foreach(delegate (string i)
            {
                str = str.Replace(i, "");
            });
            return str;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="str"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public static List<string> Splits(this string str, params string[] args)
        {
            return str.Split(args, StringSplitOptions.RemoveEmptyEntries).ToList();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="str"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public static List<string> SplitsWithTrim(this string str, params string[] args)
        {
            return (from i in str.Split(args, StringSplitOptions.RemoveEmptyEntries)
                    where !string.IsNullOrWhiteSpace(i)
                    select i.Trim()).ToList();
        }

        /// <summary>
        /// 路径是否包含中文字符
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static bool ContainsChineseChar(this string path)
        {
            if (!string.IsNullOrWhiteSpace(path))
            {
                string fileName = Path.GetFileName(path);
                string pattern = "^[一-龥]$";
                Regex regex = new Regex(pattern);
                string text = fileName;
                for (int i = 0; i < text.Length; i++)
                {
                    if (regex.IsMatch(text[i].ToString()))
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// 是否始终等于
        /// </summary>
        /// <param name="str"></param>
        /// <param name="parmas"></param>
        /// <returns></returns>
        public static bool IsAnyEqual(this string str, params string[] parmas)
        {
            if (!string.IsNullOrWhiteSpace(str))
            {
                return str.IsAnyEqual(StringComparison.InvariantCultureIgnoreCase, parmas);
            }

            return false;
        }

        /// <summary>
        /// 是否始终等于
        /// </summary>
        /// <param name="str"></param>
        /// <param name="comparison"></param>
        /// <param name="parmas"></param>
        /// <returns></returns>
        public static bool IsAnyEqual(this string str, StringComparison comparison, params string[] parmas)
        {
            if (!string.IsNullOrWhiteSpace(str))
            {
                return parmas.FirstOrDefault((string item) => item?.Equals(str, comparison) ?? false) != null;
            }

            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="str"></param>
        /// <param name="parmas"></param>
        /// <returns></returns>
        public static bool IsContins(this string str, params string[] parmas)
        {
            if (!string.IsNullOrWhiteSpace(str))
            {
                return parmas.All((string i) => str.ToLower().Contains(i.ToLower()));
            }

            return false;
        }

        /// <summary>
        /// 新的日志Id
        /// </summary>
        /// <returns></returns>
        public static string NewLogId()
        {
            return Guid.NewGuid().ToString("N");
        }
    }
}
